package com.blog.cmrpersonalblog.service.impl;

import com.blog.cmrpersonalblog.config.EmailConfig;
import com.blog.cmrpersonalblog.dto.auth.request.SendVerificationCodeRequest;
import com.blog.cmrpersonalblog.dto.auth.request.VerifyEmailCodeRequest;
import com.blog.cmrpersonalblog.dto.auth.response.EmailVerificationResponse;
import com.blog.cmrpersonalblog.entity.EmailVerification;
import com.blog.cmrpersonalblog.mapper.EmailVerificationMapper;
import com.blog.cmrpersonalblog.service.EmailVerificationService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

import jakarta.mail.internet.MimeMessage;
import java.time.LocalDateTime;
import java.util.Random;

/**
 * 邮箱验证服务实现类
 */
@Slf4j
@Service
public class EmailVerificationServiceImpl implements EmailVerificationService {

   @Resource
    private EmailVerificationMapper emailVerificationMapper;

   @Resource
    private JavaMailSender mailSender;

   @Resource
    private TemplateEngine templateEngine;

   @Resource
    private EmailConfig emailConfig;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public EmailVerificationResponse sendVerificationCode(SendVerificationCodeRequest request, 
                                                         String ipAddress, String userAgent) {
        try {
            String email = request.getEmail();
            String verificationType = request.getVerificationType();

            // 1. 检查发送频率限制
            if (!canSendVerification(email, verificationType)) {
                Integer remainingCount = getRemainingDailyCount(email);
                return EmailVerificationResponse.rateLimited(
                    "发送过于频繁，请稍后再试", 
                    emailConfig.getSendIntervalSeconds(), 
                    remainingCount
                );
            }

            // 2. 检查每日发送限制
            LocalDateTime today = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0);
            Integer todayCount = emailVerificationMapper.countTodaySent(email, today);
            if (todayCount >= emailConfig.getDailyLimit()) {
                return EmailVerificationResponse.error("今日发送次数已达上限，请明天再试");
            }

            // 3. 生成验证码
            String verificationCode = generateVerificationCode();

            // 4. 保存验证码记录
            EmailVerification verification = new EmailVerification();
            verification.setEmail(email);
            verification.setVerificationCode(verificationCode);
            verification.setVerificationType(verificationType);
            verification.setIsUsed(0);
            verification.setExpireTime(LocalDateTime.now().plusMinutes(emailConfig.getCodeExpireMinutes()));
            verification.setIpAddress(ipAddress);
            verification.setUserAgent(userAgent);
            verification.setCreateTime(LocalDateTime.now());

            emailVerificationMapper.insert(verification);

            // 5. 异步发送邮件
            sendVerificationEmailAsync(email, verificationCode, verificationType);

            log.info("验证码发送成功: email={}, type={}, code={}", email, verificationType, verificationCode);

            return EmailVerificationResponse.success(
                "验证码已发送到您的邮箱，请查收", 
                emailConfig.getCodeExpireMinutes()
            );

        } catch (Exception e) {
            log.error("发送验证码失败: email={}, type={}, error={}", 
                     request.getEmail(), request.getVerificationType(), e.getMessage(), e);
            return EmailVerificationResponse.error("发送失败，请稍后重试");
        }
    }

    @Override
    public boolean verifyCode(VerifyEmailCodeRequest request) {
        try {
            EmailVerification verification = emailVerificationMapper.selectValidVerification(
                request.getEmail(), request.getVerificationCode(), request.getVerificationType()
            );

            if (verification == null) {
                log.warn("验证码验证失败: email={}, code={}, type={} - 验证码不存在或已过期", 
                        request.getEmail(), request.getVerificationCode(), request.getVerificationType());
                return false;
            }

            if (verification.getIsUsed() == 1) {
                log.warn("验证码验证失败: email={}, code={}, type={} - 验证码已使用", 
                        request.getEmail(), request.getVerificationCode(), request.getVerificationType());
                return false;
            }

            if (verification.getExpireTime().isBefore(LocalDateTime.now())) {
                log.warn("验证码验证失败: email={}, code={}, type={} - 验证码已过期", 
                        request.getEmail(), request.getVerificationCode(), request.getVerificationType());
                return false;
            }

            return true;
        } catch (Exception e) {
            log.error("验证码校验异常: email={}, code={}, type={}, error={}", 
                     request.getEmail(), request.getVerificationCode(), request.getVerificationType(), e.getMessage());
            return false;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean verifyAndUseCode(VerifyEmailCodeRequest request) {
        try {
            if (!verifyCode(request)) {
                return false;
            }

            // 标记验证码为已使用
            EmailVerification verification = emailVerificationMapper.selectValidVerification(
                request.getEmail(), request.getVerificationCode(), request.getVerificationType()
            );

            if (verification != null) {
                verification.setIsUsed(1);
                verification.setUseTime(LocalDateTime.now());
                emailVerificationMapper.updateById(verification);

                log.info("验证码使用成功: email={}, code={}, type={}", 
                        request.getEmail(), request.getVerificationCode(), request.getVerificationType());
                return true;
            }

            return false;
        } catch (Exception e) {
            log.error("验证码使用异常: email={}, code={}, type={}, error={}", 
                     request.getEmail(), request.getVerificationCode(), request.getVerificationType(), e.getMessage());
            return false;
        }
    }

    @Override
    public boolean isCodeValid(String email, String verificationCode, String verificationType) {
        VerifyEmailCodeRequest request = new VerifyEmailCodeRequest();
        request.setEmail(email);
        request.setVerificationCode(verificationCode);
        request.setVerificationType(verificationType);
        return verifyCode(request);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean invalidateVerifications(String email, String verificationType) {
        try {
            Integer count = emailVerificationMapper.invalidateVerifications(email, verificationType);
            log.info("验证码失效成功: email={}, type={}, count={}", email, verificationType, count);
            return count > 0;
        } catch (Exception e) {
            log.error("验证码失效失败: email={}, type={}, error={}", email, verificationType, e.getMessage());
            return false;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer cleanExpiredVerifications() {
        try {
            LocalDateTime expireTime = LocalDateTime.now().minusDays(7); // 清理7天前的过期记录
            Integer count = emailVerificationMapper.deleteExpiredVerifications(expireTime);
            log.info("清理过期验证码成功: count={}", count);
            return count;
        } catch (Exception e) {
            log.error("清理过期验证码失败: error={}", e.getMessage());
            return 0;
        }
    }

    @Override
    public boolean canSendVerification(String email, String verificationType) {
        try {
            LocalDateTime limitTime = LocalDateTime.now().minusSeconds(emailConfig.getSendIntervalSeconds());
            Integer recentCount = emailVerificationMapper.countSentInTimeRange(email, verificationType, limitTime);
            return recentCount == 0;
        } catch (Exception e) {
            log.error("检查发送频率限制失败: email={}, type={}, error={}", email, verificationType, e.getMessage());
            return false;
        }
    }

    @Override
    public Integer getRemainingDailyCount(String email) {
        try {
            LocalDateTime today = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0);
            Integer todayCount = emailVerificationMapper.countTodaySent(email, today);
            return Math.max(0, emailConfig.getDailyLimit() - todayCount);
        } catch (Exception e) {
            log.error("获取剩余发送次数失败: email={}, error={}", email, e.getMessage());
            return 0;
        }
    }

    @Override
    public String generateVerificationCode() {
        Random random = new Random();
        return String.format("%06d", random.nextInt(1000000));
    }

    /**
     * 异步发送验证邮件
     */
    @Async("emailTaskExecutor")
    public void sendVerificationEmailAsync(String email, String verificationCode, String verificationType) {
        try {
            sendVerificationEmail(email, verificationCode, verificationType);
            log.info("异步邮件发送成功: email={}, type={}", email, verificationType);
        } catch (Exception e) {
            log.error("异步邮件发送失败: email={}, type={}, error={}", email, verificationType, e.getMessage());
            // 异步发送失败不影响主流程，只记录日志
        }
    }

    /**
     * 发送验证邮件
     */
    private void sendVerificationEmail(String email, String verificationCode, String verificationType) {
        try {
            MimeMessage message = mailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");

            helper.setFrom(emailConfig.getFromEmail(), emailConfig.getFromName());
            helper.setTo(email);
            helper.setSubject(emailConfig.getTemplates().getVerificationSubject());

            // 使用Thymeleaf模板生成邮件内容
            Context context = new Context();
            context.setVariable("verificationCode", verificationCode);
            context.setVariable("expireMinutes", emailConfig.getCodeExpireMinutes());
            context.setVariable("verificationType", getVerificationTypeText(verificationType));

            String htmlContent = templateEngine.process("email/verification-code", context);
            helper.setText(htmlContent, true);

            mailSender.send(message);
            log.info("验证邮件发送成功: email={}, type={}", email, verificationType);

        } catch (Exception e) {
            log.error("验证邮件发送失败: email={}, type={}, error={}", email, verificationType, e.getMessage());
            throw new RuntimeException("邮件发送失败", e);
        }
    }

    /**
     * 获取验证类型文本
     */
    private String getVerificationTypeText(String verificationType) {
        switch (verificationType) {
            case "REGISTER":
                return "注册验证";
            case "RESET_PASSWORD":
                return "密码重置";
            case "CHANGE_EMAIL":
                return "更换邮箱";
            default:
                return "邮箱验证";
        }
    }
}
